package com.breeze.components.core.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author breeze
 */
@Slf4j
public class DateUtil extends cn.hutool.core.date.DateUtil {

  private static final Log logger = LogFactory.getLog(DateUtil.class);

  public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
  public static final String DEFAULT_DATE_PATTERN2 = "yyyy.MM.dd";
  public static final String DEFAULT_DATE_PATTERN_1 = "yyyy/MM/dd";
  public static final String DEFAULT_DATE_PATTERN_2 = "yyyyMMdd";
  public static final String DEFAULT_DATE_PATTERN_3 = "yyyy-MM";
  public static final String DEFAULT_DATE_PATTERN_4 = "HHmmss";
  public static final String DEFAULT_DATE_PATTERN_5 = "yyyy-MM-dd HH:mm";
  public static final String DEFAULT_DATE_PATTERN_TIME = "yyyy-MM-dd HH:mm:ss";
  public static final String DATE_TIME_PATTERN = "yyyyMMddHHmmss";
  public static final String DATE_PATTERN = "yyyyMMdd";
  public static final String DEFAULT_DATEPATTERN_CN = "yyyy年MM月dd";
  public static final String DEFAULT_DATEPATTERN_CN_1 = "yyyy年MM月dd日";
  public static final String DEFAULT_DATEPATTERN_CN_2 = "yy年MM月";
  public static final String DEFAULT_DATEPATTERN_CN_3 = "MM月dd日";
  public static final String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";
  public static final String TIME_PATTERN = "HH:mm:ss";
  public static final String TIME_PATTERN_1 = "HHmmss";
  public static final String TIME_PATTERN_2 = "HH:mm";
  public static final long DAY_SECONDS = 24 * 60 * 60 * 1000;

  /**
   * 生成日期文件路径
   *
   * @param prefix 前缀文件夹
   * @return 文件路径
   */
  public static String dateFilePath(String prefix) {
    return prefix + "/" + DateUtil.format(new Date(), DEFAULT_DATE_PATTERN) + "/";
  }

  /**
   * 返回是否在一分钟内 不能大于当前时间秒
   *
   * @param second 秒时间戳
   * @return 返回是否在一分钟内
   */
  public static boolean inMinutes(Integer second) {
    return inMinutes(second, 60);
  }

  public static boolean inMinutes(Integer second, Integer offset) {
    long diff = diffCurrentSecondAbs(second);
    return diff >= 0 && diff <= offset;
  }

  public static long diffCurrentSecondAbs(Integer second) {
    // 时间误差取绝对值
    return Math.abs(getCurrentSecond() - second);
  }

  public static long getCurrentSecond() {
    return System.currentTimeMillis() / 1000;
  }

  public static String getDateString(Date aDate, String pattern) {
    SimpleDateFormat df;
    String returnValue = "";
    if (aDate != null) {
      df = new SimpleDateFormat(pattern);
      returnValue = df.format(aDate);
    }
    return returnValue;
  }

  public static Date convertStringToDate(String strDate, String pattern) {
    if (strDate == null) {
      return null;
    }
    SimpleDateFormat df;
    Date date = null;
    df = new SimpleDateFormat(pattern);
    try {
      date = df.parse(strDate);
    } catch (ParseException ignored) {

    }
    return date;
  }

  /**
   * 计算两个日期之间相差的天数
   *
   * @param smdate 较小的时间
   * @param bdate 较大的时间
   * @return 相差天数
   */
  public static int daysBetween(Date smdate, Date bdate) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    long betweenDays = 0;
    try {
      smdate = sdf.parse(sdf.format(smdate));

      bdate = sdf.parse(sdf.format(bdate));
      Calendar cal = Calendar.getInstance();
      cal.setTime(smdate);
      long time1 = cal.getTimeInMillis();
      cal.setTime(bdate);
      long time2 = cal.getTimeInMillis();
      betweenDays = (time2 - time1) / (1000 * 3600 * 24);
    } catch (ParseException e) {
      logger.error("daysBetween error:", e);
    }
    return Integer.parseInt(String.valueOf(betweenDays));
  }

  /**
   * 计算一个日期加指定天数后的日期
   *
   * <p>较小的时间 较大的时间
   *
   * @return 相差天数
   */
  public static Date addDays(Date d, int added) {
    Calendar ca = Calendar.getInstance();
    ca.setTime(d);
    // 30为增加的天数，可以改变的
    ca.add(Calendar.DATE, added);
    d = ca.getTime();
    return d;
  }

  /** 计算指定日期下月的某一天，如果超过下月最大天数则取最后一天 */
  public static Date getMonthDay(Date start, int day) {
    Date resultDate;
    Calendar ca = Calendar.getInstance();
    ca.setTime(start);
    ca.add(Calendar.MONTH, 1);
    ca.set(Calendar.DAY_OF_MONTH, 1);
    int lastDay = ca.getActualMaximum(Calendar.DAY_OF_MONTH);
    ca.set(Calendar.DAY_OF_MONTH, Math.min(day, lastDay));
    resultDate = ca.getTime();
    return resultDate;
  }

  /** 获取00:00:00 */
  public static Date parseStartDate(Date date) {
    if (date == null) {
      return null;
    }
    try {
      return new SimpleDateFormat(DEFAULT_DATE_PATTERN_TIME)
          .parse(new SimpleDateFormat(DEFAULT_DATE_PATTERN).format(date) + " 00:00:00");
    } catch (ParseException e) {
      logger.error("parseStartDate异常: ", e);
      return null;
    }
  }

  /** 获取年月日 */
  public static Date parseShortDate(Date date) {
    if (date == null) {
      return null;
    }
    try {
      return new SimpleDateFormat(DEFAULT_DATE_PATTERN)
          .parse(new SimpleDateFormat(DEFAULT_DATE_PATTERN).format(date));
    } catch (ParseException e) {
      logger.error("parseStartDate异常: ", e);
      return null;
    }
  }

  /** 获取23:59:59 */
  public static Date parseEndDate(Date date) {
    if (date == null) {
      return null;
    }
    try {
      return new SimpleDateFormat(DEFAULT_DATE_PATTERN_TIME)
          .parse(new SimpleDateFormat(DEFAULT_DATE_PATTERN).format(date) + "  23:59:59");
    } catch (ParseException e) {
      logger.error("parseEndDate异常: ", e);
      return null;
    }
  }

  /** 格式化日期 default yyyy-MM-dd */
  public static String formatDateYmd(Date date) {
    if (date == null) {
      return null;
    }
    try {
      return new SimpleDateFormat(DEFAULT_DATE_PATTERN).format(date);
    } catch (Exception e) {
      logger.error("formatDate异常: ", e);
    }
    return null;
  }

  /** 格式化日期 default yyyy-MM-dd */
  public static Date stringToDate(String date) {
    if (date == null) {
      return null;
    }
    try {
      return new SimpleDateFormat(DEFAULT_DATE_PATTERN).parse(date);
    } catch (Exception e) {
      logger.error("formatDate异常: ", e);
    }
    return null;
  }

  /** 判断当前时间是否在[startTime, endTime]区间，注意时间格式要一致 */
  public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
    if (nowTime.getTime() == startTime.getTime() || nowTime.getTime() == endTime.getTime()) {
      return true;
    }

    Calendar date = Calendar.getInstance();
    date.setTime(nowTime);

    Calendar begin = Calendar.getInstance();
    begin.setTime(startTime);

    Calendar end = Calendar.getInstance();
    end.setTime(endTime);

    return date.after(begin) && date.before(end);
  }

  public static Date toDate(LocalDateTime ex) {
    return Date.from(ex.atZone(ZoneId.systemDefault()).toInstant());
  }

  public static Long todayBeginEpochSecond() {
    return LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
  }

  public static LocalDateTime todayBeginDateTime() {
    return LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
  }

  /**
   * @return 当月第一天0点
   */
  public static LocalDateTime getNowMonthStartDay() {
    return LocalDateTime.now().toLocalDate().withDayOfMonth(1).atStartOfDay();
  }

  /** LocalDateTime来判断是否是今天 */
  public static boolean isToday(LocalDateTime localDateTime) {
    LocalDateTime startTime = LocalDate.now().atTime(0, 0, 0);
    LocalDateTime endTime = LocalDate.now().atTime(23, 59, 59);
    return localDateTime.isAfter(startTime) && localDateTime.isBefore(endTime);
  }

  /** LocalDateTime来判断是否是昨天 */
  public static boolean isYesterday(LocalDateTime localDateTime) {
    LocalDate yesterday = LocalDate.now().minusDays(1);
    LocalDateTime startTime = yesterday.atTime(0, 0, 0);
    LocalDateTime endTime = yesterday.atTime(23, 59, 59);
    return localDateTime.isAfter(startTime) && localDateTime.isBefore(endTime);
  }

  public static boolean currentIsWeekDay() {
    return cn.hutool.core.date.DateUtil.isWeekend(new Date());
  }

  /** 当天的0时0点0分 开始时刻 */
  public static LocalDateTime currentStartDateTime() {
    return LocalDate.now().atStartOfDay();
  }

  public static List<LocalDate> parseDateListInRange(Set<Integer> collect, int maxRangeDays) {
    // 解析日期yyyyMMdd 模式下的所有日期 collect，生成时间段，最大日期间隔天数maxRangeDays （不包含）
    List<LocalDate> dateList =
        collect.stream()
            .map(DateUtil::parseYYYYMMDD)
            .filter(Objects::nonNull)
            .distinct()
            .sorted()
            .toList();
    List<LocalDate> periods = new ArrayList<>();
    LocalDate localDate = dateList.getFirst();
    periods.add(localDate);
    for (int i = 1; i < dateList.size(); i++) {
      long between = ChronoUnit.DAYS.between(localDate, dateList.get(i));
      while (between > maxRangeDays) {
        between = between - maxRangeDays + 1;
        localDate = localDate.plusDays(maxRangeDays - 1);
        periods.add(localDate);
      }
    }
    periods.add(dateList.getLast());
    return periods;
  }

  @SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
  private static LocalDate parseYYYYMMDD(Integer yyyymmdd) {
    return DateUtil.parseLocalDateTime(String.valueOf(yyyymmdd), DEFAULT_DATE_PATTERN_2)
        .toLocalDate();
  }

  public static LocalDate plusDayInWorkDay(LocalDate now, int plus) {
    LocalDate nextDate = now.plusDays(plus);
    while (cn.hutool.core.date.LocalDateTimeUtil.isWeekend(nextDate)) {
      nextDate = nextDate.plusDays(1);
    }
    return nextDate;
  }
}
